/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.ObjectModel;
using System.Data.Objects;
using System.Linq;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections;
#if _LOCALDB
  using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif

#if _LOCALDB
  namespace Oceanside.LocalDB
#else
namespace Oceanside.RemoteDB
#endif
{
    /// <summary>
    /// Every check can have one or more payments associated with it.  A payment can be a comp, cash, credit....
    /// </summary>
    public partial class TRANSACTION : INotifyPropertyChanged
    {
        public delegate void PaymentReportCallbackType(List<TRANSACTION> report, DateTime houseDate);


        [field: NonSerialized]
        public new event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            try
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
            catch (Exception excep)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PLACEHOLDER, excep);
            }
        }

        public const int CONST_PAY_CASH = 1;
        public const int CONST_PAY_CREDIT = 2;
        public const int CONST_PAY_GIFT = 3;
        public const int CONST_PAY_ACCOUNT = 4;
        public const int CONST_PAY_COUPON = 5;
        public const int CONST_PAY_VOUCHER = 6;
        public const int CONST_PAY_MISC = 7;
        public const int CONST_PAY_CHECK = 8;
        public const int CONST_NUMBER_PAYMENT_TYPES = 8;

        public const int CONST_TENDER_CASH = 1;
        public const int CONST_TENDER_VISA = 2;
        public const int CONST_TENDER_MC = 3;
        public const int CONST_TENDER_DISC = 4;
        public const int CONST_TENDER_AMEX = 5;
        public const int CONST_TENDER_DNCLB = 6;
        public const int CONST_TENDER_OTHER = 7;
        public const int CONST_TENDER_JCB = 8;
        public const int CONST_TENDER_GIFT = 9;
        public const int CONST_TENDER_ACCOUNT = 10;
        public const int CONST_TENDER_COUPON = 11;
        public const int CONST_TENDER_VOUCHER = 12;
        public const int CONST_TENDER_CHECK = 13;
        public const int CONST_NUMBER_TENDER_TYPES = 13;

        public static Hashtable TenderIdToNameHash = new Hashtable(CONST_NUMBER_TENDER_TYPES);
        public static Hashtable TenderIdToPaymentTypeHash = new Hashtable(CONST_NUMBER_TENDER_TYPES);
        static TRANSACTION()
        {
            TenderIdToNameHash.Add(CONST_TENDER_CASH, "CASH");
            TenderIdToNameHash.Add(CONST_TENDER_VISA, "VISA");
            TenderIdToNameHash.Add(CONST_TENDER_MC, "MASTERCARD");
            TenderIdToNameHash.Add(CONST_TENDER_DISC, "DISCOVER");
            TenderIdToNameHash.Add(CONST_TENDER_AMEX, "AMEX");
            TenderIdToNameHash.Add(CONST_TENDER_DNCLB, "DINNERS CLUB");
            TenderIdToNameHash.Add(CONST_TENDER_OTHER, "OTHER");
            TenderIdToNameHash.Add(CONST_TENDER_JCB, "JCB");
            TenderIdToNameHash.Add(CONST_TENDER_GIFT, "GIFT");
            TenderIdToNameHash.Add(CONST_TENDER_ACCOUNT, "ACCOUNT");
            TenderIdToNameHash.Add(CONST_TENDER_COUPON, "COUPON");
            TenderIdToNameHash.Add(CONST_TENDER_VOUCHER, "VOUCHER");

            TenderIdToPaymentTypeHash.Add(CONST_TENDER_CASH, "CASH");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_VISA, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_MC, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_DISC, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_AMEX, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_DNCLB, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_OTHER, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_JCB, "CREDIT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_GIFT, "GIFT_CARD");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_ACCOUNT, "ACCOUNT");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_COUPON, "COUPON");
            TenderIdToPaymentTypeHash.Add(CONST_TENDER_VOUCHER, "VOUCHER");
        }
        public static string PopupSelectTransactionType(out Int64 chosenDbId)
        {
            chosenDbId = DominicaEntities.CONST_ALL_DB_OBJECTS_WILDCARD;
            try
            {
                List<String> stringsList = new List<string>();
                List<Int64> pidsList = new List<Int64>();

                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    var q = from PRODUCT_GROUP in context.PRODUCT_GROUPS where PRODUCT_GROUP.IsDeleted == false select PRODUCT_GROUP;

                    if (q.Any())
                    {
                        stringsList.Add("All Groups");
                        pidsList.Add(DominicaEntities.CONST_ALL_DB_OBJECTS_WILDCARD);
                        foreach (PRODUCT_GROUP pg in q)
                        {
                            stringsList.Add(pg.Name);
                            pidsList.Add(pg.Id);
                        }
                    }
                }

                BoundObjectStringSelectionListBox dialog = new BoundObjectStringSelectionListBox(stringsList, pidsList);
                dialog.SetMessage("Select a Main Product Category and the System will Print all Product Sales for the Main Product Category you have selected.");
                dialog.ShowDialog();

                if (BoundObjectStringSelectionListBox.LastResponse == UserResponse.ENTER)
                {
                    chosenDbId = BoundObjectStringSelectionListBox.ChosenDbId;
                    return BoundObjectStringSelectionListBox.ChosenString;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_REPORT_ERROR, exc);
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        private class SearchPaymentsInputs
        {
            public Int64 TransId { get; set; }
            public int Take { get; set; }
            public int Skip { get; set; }
        }

        /// <summary>
        /// 
        /// </summary>
        private static Func<DominicaEntities, SearchPaymentsInputs, IQueryable<TRANSACTION>> SearchPaymentsQuery =
            CompiledQuery.Compile((DominicaEntities context, SearchPaymentsInputs inputs) =>
                          (from T in context.TRANSACTIONS
                           where T.Id == inputs.TransId
                           orderby T.Id
                           select T).Skip(inputs.Skip).Take(inputs.Take));

        /// <summary>
        /// 
        /// </summary>
        private static Func<DominicaEntities, DateTime, IQueryable<BUSINESS_DAY>> GetHouseCheckout =
            CompiledQuery.Compile((DominicaEntities context, DateTime dateTime) =>
                          (from BUSINESS_DAY in context.BUSINESS_DAYS
                           where BUSINESS_DAY.BusinessDayDateStamp.Day.Equals(dateTime.Date.Day)
                           where BUSINESS_DAY.BusinessDayDateStamp.Month.Equals(dateTime.Date.Month)
                           where BUSINESS_DAY.BusinessDayDateStamp.Year.Equals(dateTime.Date.Year)
                           select BUSINESS_DAY));
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="tranId"></param>
        /// <param name="skip"></param>
        /// <param name="take"></param>
        /// <returns></returns>
        public static ObservableCollection<TRANSACTION> SearchForTransId(DominicaEntities context,
            Int64 tranId,
            int skip, int take)
        {
            SearchPaymentsInputs inputs =
                new SearchPaymentsInputs { TransId = tranId, Take = take, Skip = skip };

            return new ObservableCollection<TRANSACTION>(SearchPaymentsQuery(context, inputs).ToList());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="tranId"></param>
        /// <param name="skip"></param>
        /// <param name="take"></param>
        /// <returns></returns>
        public static List<TRANSACTION> GetCreditPayments(Int64 hcId, PaymentReportCallbackType callBack)
        {
            List<TRANSACTION> payments = new List<TRANSACTION>();
            try
            {
                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    context.PAYMENTS.MergeOption = MergeOption.NoTracking;
                    BUSINESS_DAY businessDay = context.BUSINESS_DAYS.Where(hc => hc.Id == hcId).FirstOrDefault();
                    if (businessDay != null)
                    {
                        businessDay.SHIFTS.Load();

                        List<SHIFT> userCheckoutList = businessDay.SHIFTS.ToList();
                        foreach (SHIFT userCheckout in userCheckoutList)
                        {
                            userCheckout.ORDERS.Load();
                            List<ORDER> checks = userCheckout.ORDERS.ToList();
                            foreach (ORDER check in checks)
                            {
                                check.TRANSACTIONS.Load();
                                foreach (TRANSACTION payment in check.TRANSACTIONS)
                                {
                                    if (payment.TransactionType == TRANSACTION.CONST_PAY_GIFT ||
                                        payment.TransactionType == TRANSACTION.CONST_PAY_CREDIT)
                                    {
                                        payments.Add(payment);
                                    }
                                }
                            }
                        }

                        if (payments.Count != 0)
                        {
                            Oceanside.Constants.MainDispatcher.Invoke(callBack, payments, businessDay.CheckoutDateStamp);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_REPORT_ERROR, ex);
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
            return payments;
        }
    }
}
